package com.pz.chat.netty_ws.handlers;

import com.alibaba.fastjson2.JSON;
import com.pz.chat.constant.MessageCodeEnum;
import com.pz.chat.constant.MessageTypeEnum;
import com.pz.chat.entity.ChatMessageEntity;
import com.pz.chat.config.netty.NettyConfig;
import com.pz.chat.utils.SpringUtils;
import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;


@Slf4j
public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
    private final WebSocketClientHandshaker handshake;
    private ChannelPromise handshakeFuture;

    public WebSocketClientHandler(WebSocketClientHandshaker handShaker) {
        this.handshake = handShaker;
    }

    public ChannelFuture handshakeFuture() {
        return handshakeFuture;
    }

    private final NettyConfig nettyConfig = SpringUtils.getBean("nettyConfig");

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        log.info("handlerAdded>>>...");
        handshakeFuture = ctx.newPromise();
    }

    /**
     *  创建连接,向服务端发送握手请求
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        handshake.handshake(ctx.channel());
    }

    /**
     *  连接关闭
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.info("WebSocket Client disconnected!, channelId-{}", ctx.channel().id().toString());
        assert nettyConfig != null;
        nettyConfig.getChannelGroup().remove(ctx.channel());
    }

    /**
     *  读取数据
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel ch = ctx.channel();
        if (!handshake.isHandshakeComplete()) {
            try {
                handshake.finishHandshake(ch, (FullHttpResponse) msg);
                log.info("WebSocket Client connected!");
                handshakeFuture.setSuccess();
                // 握手成功 向其他netty-ws服务器发送注册消息
                ChatMessageEntity registerMsg = new ChatMessageEntity(nettyConfig.getNettyDiscoveryIp()+":"+nettyConfig.getWsPort(),
                        "0", "",MessageTypeEnum.CLIENT_INIT_USERID.getType(), 0, 1);
                log.info("客户端的注册消息-{}", registerMsg);
                ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(registerMsg)));
            } catch (WebSocketHandshakeException e) {
                log.error("WebSocket Client failed to connect");
                handshakeFuture.setFailure(e);
            }
            return;
        }

        if (msg instanceof FullHttpResponse) {
            FullHttpResponse response = (FullHttpResponse) msg;
            throw new IllegalStateException(
                    "Unexpected FullHttpResponse (getStatus=" + response.status() +
                            ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
        }

        WebSocketFrame frame = (WebSocketFrame) msg;
        if (frame instanceof TextWebSocketFrame) {
            TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
            // 转发消息
            String textMsg = textFrame.text();
            log.info("客户端收到消息-{}", textMsg);
            ChatMessageEntity chatMessage = JSON.to(ChatMessageEntity.class, textMsg);
            if(chatMessage.getType().equals(MessageTypeEnum.PRIVATE_MSG.getType())) {
                // 处理私发消息的转发
                Channel targetChannel = nettyConfig.getChannel(chatMessage.getToId());
                if(targetChannel != null) {
                    // 私发消息转发
                    targetChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(chatMessage)));
                } else {
                    log.error("redis 与 本地的channel信息不一致 {}",chatMessage);
                }
            }

        } else if (frame instanceof PongWebSocketFrame) {
            log.info("WebSocket Client received pong");
        } else if (frame instanceof CloseWebSocketFrame) {
            log.info("WebSocket Client received closing");
            ch.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error(cause.getMessage());
        if (!handshakeFuture.isDone()) {
            handshakeFuture.setFailure(cause);
        }
        ctx.close();
    }
}
